package com.lge.pitchingcoins.ui.clients.layer;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.net.nsd.NsdServiceInfo;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.view.Window;
import android.view.WindowManager;

import com.lge.pitchingcoins.R;
import com.lge.pitchingcoins.ui.clients.ClientsMainActivityWithCocos;
import com.lge.pitchingcoins.util.PitchingCoinsLog;
import com.lge.pitchingcoins.util.Util;
import com.lge.pitchingcoins.util.sessions.ClientsSession;
import com.lge.pitchingcoins.util.sessions.GameCmdManager;
import com.lge.pitchingcoins.util.sessions.GameCmdManager.GameCmdSendDTO;
import com.lge.pitchingcoins.util.sessions.GameCmdProcessor;
import com.lge.pitchingcoins.util.sessions.ServiceHelper;

import org.cocos2d.actions.interval.CCJumpTo;
import org.cocos2d.actions.interval.CCMoveBy;
import org.cocos2d.actions.interval.CCMoveTo;
import org.cocos2d.layers.CCLayer;
import org.cocos2d.layers.CCMultiplexLayer;
import org.cocos2d.nodes.CCSprite;
import org.cocos2d.types.CGPoint;

import java.util.ArrayList;

public class GamePlayForClientsLayer extends CCLayer {
    public static final int WAITING_SERVER_DIALOG_SHOW = 1000;
    public static final int CHANGE_IS_GAME_PLAYING = 1001;
    public static final int WAITING_SERVER_RESPONSE_DIALOG_SHOW = 1002;
    public static final int UNLOCK_HOMEKEY = 1003;
    public static final int REMOVE_CHILDREN_AFTER_3SECONDS = 1004;
    
    public static final int MAX_COUNT = 20;
    
    
    private ArrayList<AccelValue> arValue = new ArrayList<AccelValue>();

    private GamePlayForClientsLayer myself = null;
    private Context mContext = null;
    private String clientNickname = null;

    private ServiceHelper serviceHelper = null;
    private boolean isStartDiscover = false;
    private boolean isGamePlaying = false;
    private boolean isMyTurn = false;
    
    private ClientsSession clientsSession = null;

    private GameCmdManager mGameCmdManager = null;
    private GameCmdProcessor mGameCmdProcessor = null;

    private Dialog waitingServerDialog = null;
    private Dialog waitingServerResponseDialog = null;
    
    private SensorManager mSensorManager = null;
    private long mApplyTime = 0;
    private int mSenGap = 3000;
    private int LIMIT_FORCE = 8;
    
    // To Draw
    private CCSprite sprite = null;
    
    
    private Handler mHandler = new Handler() {
        @Override
        public void dispatchMessage(Message msg) {
            if (msg.what == WAITING_SERVER_DIALOG_SHOW) {
                waitingServerDialog.show();
            } else if (msg.what == CHANGE_IS_GAME_PLAYING) {
                Util.setHomeKeyLock((Activity)mContext, isGamePlaying);

                if (isGamePlaying) {
                    waitingServerResponseDialog.dismiss();
                } else {
                    waitingServerResponseDialog.show();
                }
            } else if (msg.what == WAITING_SERVER_RESPONSE_DIALOG_SHOW) {
                waitingServerResponseDialog.show();
            } else if (msg.what == UNLOCK_HOMEKEY) {
                Util.setHomeKeyLock((Activity)mContext, false);
            } else if (msg.what == REMOVE_CHILDREN_AFTER_3SECONDS) {
                Handler delayHandler = new Handler();
                delayHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        removeAllChildren(true);
                    }
                }, 3000);
            }
        }
    };
    
    SensorEventListener mSensorListener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            sensorChanged(event);
        }
        
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
            
        }
    };


    // Constructors
    public GamePlayForClientsLayer(Context context) {
        mContext = context;

        initComponent();
    }

    
    // Getters and Setters
    public boolean isGamePlaying() {
        return isGamePlaying;
    }

    public void setGamePlaying(boolean isGamePlaying) {
        this.isGamePlaying = isGamePlaying;

        mHandler.sendEmptyMessage(CHANGE_IS_GAME_PLAYING);
    }
    
    public boolean isMyTurn() {
        return isMyTurn;
    }
    
    public void setMyTurn(boolean isMyTurn) {
        this.isMyTurn = isMyTurn;
        
        if (isMyTurn) {
            sprite = CCSprite.sprite("coin.png");
            sprite.setPosition(CGPoint.make(getContentSize().width / 2, getContentSize().height / 3));
            addChild(sprite, 1, 1000);
        } else {
            mHandler.sendEmptyMessage(REMOVE_CHILDREN_AFTER_3SECONDS);
        }
    }
    

    // Callback Methods
    @Override
    public void onEnter() {
        if (isGamePlaying) {
            PitchingCoinsLog.d("Enter while game is playing");
        } else {
            if (serviceHelper != null) {
                if (!isStartDiscover) {
                    isStartDiscover = true;
                    serviceHelper.discoverServices();
                }
            }

            clientNickname = ((ClientsMainActivityWithCocos)mContext).getNickname();
            clientNickname += "_" + Build.ID;
            
            PitchingCoinsLog.d("My Nickname: " + clientNickname);
            
            mHandler.sendEmptyMessage(WAITING_SERVER_DIALOG_SHOW);
        }
        
        if (mSensorManager != null) { 
            mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);
        }
        
        super.onEnter();
    }

    @Override
    public void onExit() {
        if (isGamePlaying) {
            if (clientsSession != null) {
                clientsSession.sendMessageToServer("IL " + clientNickname);
                clientsSession = null;
            }
            
            PitchingCoinsLog.d("Exit while game is playing");
        } else {
            if (serviceHelper != null) {
                if (isStartDiscover) {
                    stopDiscover();
                }
            }

            if (clientsSession != null) {
                clientsSession.sendMessageToServer("IL " + clientNickname);
                clientsSession = null;
            }
            
            mSensorManager.unregisterListener(mSensorListener);
        }

        super.onExit();
    }

    public void onServiceFound(NsdServiceInfo serviceInfo) {
        PitchingCoinsLog.d(serviceInfo.getServiceName() + " Service Found");
        if (serviceInfo != null) {
            serviceHelper.reloveService(serviceInfo);
            stopDiscover();
        }
    }

    public void onServiceLost(NsdServiceInfo serviceInfo) {
        restartDiscoverService();
    }
    
    public void onServiceResolved(NsdServiceInfo serviceInfo) {
        if (serviceInfo != null) {
            startGame(serviceInfo);
        }
    }
    
    @Override
    public boolean ccKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
        case KeyEvent.KEYCODE_BACK:
            if (isGamePlaying) {
                return isGamePlaying;
            }
        }
        
        return super.ccKeyDown(keyCode, event);
    }
    
    public void onMessageReceived(String message) {
        PitchingCoinsLog.d("Client: " + message);

        if (message.equals("IL")) {
            clientsSession = null;
            setGamePlaying(false);
            
            if (waitingServerDialog.isShowing()) {
                waitingServerDialog.dismiss();
            }
            
            if (waitingServerResponseDialog.isShowing()) {
                waitingServerResponseDialog.dismiss();
            }
            
            ((CCMultiplexLayer)getParent()).setTag(0);
            ((CCMultiplexLayer)getParent()).switchTo(0);
        } else if (message.equals("WRU")) {
            sendMessageToServer("IM " + clientNickname);
            PitchingCoinsLog.d("IM " + clientNickname);
        } else if (message.equals("GS")) {
            setGamePlaying(true);
        } else if (message.equals("GO")) {
            setGamePlaying(false);
        } else if (message.equals("MT")) {
            setMyTurn(true);
        }
//        } else if (message.equals("NMT")) {
//            setMyTurn(false);
//        }

        // TODO get server message

    }


    // Member Methods
    public void initComponent() {
        myself = this;
        this.setIsKeyEnabled(true);

        serviceHelper = new ServiceHelper(mContext);
        serviceHelper.setCallback(this);
        serviceHelper.initializeNsd();

        initWaitingServerDialog();
        initWaitingServerResponseDialog();

        mGameCmdManager = GameCmdManager.getInstance();
        mGameCmdProcessor = GameCmdProcessor.getInstance();
        
        mSensorManager = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE);
        mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);
        
//        sprite = CCSprite.sprite("coin.png");
//        sprite.setPosition(CGPoint.make(getContentSize().width / 2, getContentSize().height / 3));
//        addChild(sprite, 1, 1000);
    }

    public void initWaitingServerDialog() {
        waitingServerDialog = new Dialog(mContext);
        waitingServerDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        waitingServerDialog.setContentView(R.layout.view_circle_progress_bar);
        waitingServerDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
        waitingServerDialog.setOnCancelListener(new OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialogInterface) {
                waitingServerDialog.dismiss();

                mHandler.sendEmptyMessage(UNLOCK_HOMEKEY);
                
                ((CCMultiplexLayer)getParent()).setTag(0);
                ((CCMultiplexLayer)getParent()).switchTo(0);
            }
        });
    }
    
    public void initWaitingServerResponseDialog() {
        waitingServerResponseDialog = new Dialog(mContext);
        waitingServerResponseDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        waitingServerResponseDialog.setContentView(R.layout.view_circle_progress_bar);
        waitingServerResponseDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
        waitingServerResponseDialog.setOnCancelListener(new OnCancelListener() {
            
            @Override
            public void onCancel(DialogInterface dialogInterface) {
                waitingServerResponseDialog.dismiss();
                
                mHandler.sendEmptyMessage(UNLOCK_HOMEKEY);
                
                ((CCMultiplexLayer)getParent()).setTag(0);
                ((CCMultiplexLayer)getParent()).switchTo(0);                
            }
        });
    }

    public void stopDiscover() {
        isStartDiscover = false;
        serviceHelper.stopDiscovery();
    }

    public void restartDiscoverService() {
        if (serviceHelper != null) {
            if (isStartDiscover) {
                stopDiscover();
                serviceHelper.discoverServices();
                isStartDiscover = true;
            }
        }
    }

    public void startGame(NsdServiceInfo serviceInfo) {
        waitingServerDialog.dismiss();
        
        clientsSession = new ClientsSession(mContext, serviceInfo.getHost().getHostAddress(), serviceInfo.getPort());
        clientsSession.setCallback(this);
        
        mHandler.sendEmptyMessage(WAITING_SERVER_RESPONSE_DIALOG_SHOW);
    }

    public void sendMessageToServer(String message) {
        PitchingCoinsLog.d("sendMessageToServer");
        if (clientsSession != null) {
            clientsSession.sendMessageToServer(message);
        }
    }

    public void sendMessageToServer(float x, float y, float z, int force) {
        GameCmdSendDTO data = mGameCmdManager.new GameCmdSendDTO(clientNickname, x, y, z, force);
        String message = data.toJSONString();
        PitchingCoinsLog.d(message);

        sendMessageToServer(message);
    }
    
    public void sensorChanged(SensorEvent event) {
        if (isGamePlaying) {
            if (isMyTurn) {
                switch (event.sensor.getType()) {
                case Sensor.TYPE_ACCELEROMETER:
                    AccelValue accelValue = new AccelValue();
                    accelValue.value[0] = event.values[0];
                    accelValue.value[1] = event.values[1];
                    accelValue.value[2] = event.values[2];
                    accelValue.time = event.timestamp;

                    if (arValue.size() == MAX_COUNT) {
                        arValue.remove(0);
                    }
                    arValue.add(accelValue);

                    long now = System.currentTimeMillis();

                    if (now - mApplyTime < mSenGap) {
                        break;
                    }

                    float[] min = new float[] { 100, 100, 100 };
                    float[] max = new float[] { -100, -100, -100 };
                    float[] difference = new float[3];

                    for (int i = arValue.size() - 1; i >= 0; i--) {
                        AccelValue v = arValue.get(i);
                        for (int j = 0; j < 3; j++) {
                            min[j] = Math.min(min[j], v.value[j]);
                            max[j] = Math.max(max[j], v.value[j]);
                        }
                    }

                    for (int j = 0; j < 3; j++) {
//                        difference[j] = Math.abs(max[j] - min[j]);
                        difference[j] = (max[j] + min[j]) / 2;
                    }

                    int force = (int)((Math.abs(difference[0]) + Math.abs(difference[1]) + Math.abs(difference[2])) / 3);

                    if (force >= LIMIT_FORCE) {
                        mApplyTime = now;

                        if (force != 0) {
                            PitchingCoinsLog.d("Pitch coins");
                            sendMessageToServer(difference[0], -difference[1], difference[2], force);

                            sprite.runAction(CCMoveBy.action(10 / force, CGPoint.make(getContentSize().width / 2, getContentSize().height + sprite.getContentSize().height)));
                            force = 0;
                            
                            arValue.clear();
                            setMyTurn(false);
                        }
                    }
                    break;
                }
            } else {
                // It is not my turn
//                PitchingCoinsLog.d("It is not my Turn");
            }
        } else {
            // Game is not playing
//            PitchingCoinsLog.d("Game is not playing");
        }
    }

    
    // Inner Classes
    class AccelValue {
        float[] value = new float[3];
        long time = 0;
    }
}
